package com.lzh.persevere.aop;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.lzh.persevere.model.entity.SysExceptionLog;
import com.lzh.persevere.model.entity.SysOperationLog;
import com.lzh.persevere.model.entity.User;
import com.lzh.persevere.security.LoginUser;
import com.lzh.persevere.service.SysExceptionLogService;
import com.lzh.persevere.service.SysOperationLogService;
import com.lzh.persevere.service.impl.SearcherService;
import com.lzh.persevere.utils.IpUtil;
import com.lzh.persevere.utils.RequestHolder;
import com.lzh.persevere.utils.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Objects;


/**
 * 系统日志切面类
 *
 * @author luzhiheng
 * @since 2025-08-20
 */
@Aspect
@Component
public class SystemLogAspect {

    @Resource
    private SysOperationLogService sysOperationLogService;

    @Resource
    private SearcherService searcherService;

    @Resource
    private SysExceptionLogService sysExceptionLogService;

    private static Logger LOGGER = LoggerFactory.getLogger(SystemLogAspect.class);

    /**
     * 定义切点@PointCut
     * 在注解位置切入代码
     */
//    @Pointcut("@annotation(com.lzh.persevere.annotation.LogAnnotation)")
//    public void logPointCut() {
//    }
    @Pointcut("execution(* com.lzh.persevere.controller..*.*(..))")
    public void logPointCut() {
    }

    /**
     * 环绕通知
     * 在执行方法之前打印获取的参数内容
     *
     * @param joinPoint 切点
     * @return Object
     * @throws Throwable 抛出异常
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        request.setCharacterEncoding("UTF-8");

        LOGGER.info("URL: {}", request.getRequestURL().toString());
        LOGGER.info("HTTP请求类型: {}", request.getMethod());
        LOGGER.info("执行方法: {}", joinPoint);
        LOGGER.info("传递参数: {}", Arrays.toString(joinPoint.getArgs()));
        LOGGER.info("IP地址:   {}: ", request.getRemoteAddr());

        SysOperationLog logEntity = new SysOperationLog();
        String url = request.getRequestURL().toString();
        url = url.substring(21);
        System.out.println("请求接口：" + url);
        logEntity.setRequestInterface(url);

        String requestMethod = request.getMethod();
        System.out.println("获取请求方式" + requestMethod);
        logEntity.setRequestWay(requestMethod);

//        String requestParams = Arrays.toString(joinPoint.getArgs());
//        logEntity.setContent(requestParams);
//        System.out.println("获取请求参数" + requestParams);

        //开始调用时间
        // 计时并调用目标函数
        long start = System.currentTimeMillis();
        String ipAddr = IpUtil.getIpAddress(request);
        logEntity.setIp(ipAddr);

        String region = searcherService.getRegionInfo(ipAddr);
        logEntity.setIpSource(region);

        Map<String, String> osAndBrowserInfo = IpUtil.getOsAndBrowserInfo(request);
        // 操作系统
        logEntity.setPlatform(osAndBrowserInfo.get("OS"));
        // 浏览器
        logEntity.setBrowser(osAndBrowserInfo.get("BROWSER"));
        //获取执行时间
        Date day = new Date();
        logEntity.setCreateTime(day);
        //获取切入点属性
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();

//        //获取操作
//        LogAnnotation myLog = method.getAnnotation(LogAnnotation.class);
//        if (myLog != null) {
//            String message = myLog.message();
//            System.out.println("用户行为：" + message);
//            logEntity.setUserBehavior(message);
//            logEntity.setInterfaceName(message);
//        }

        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser != null) {
            User user = loginUser.getUser();
            if (user != null) {
                logEntity.setCreateUserId(String.valueOf(user.getId()));
            }
        }
        Object proceed = joinPoint.proceed();
        logEntity.setRequestTime(System.currentTimeMillis() - start);
        sysOperationLogService.save(logEntity);
        return proceed;
    }

    @Pointcut("execution(* com.lzh.persevere.controller..*.*(..))")
    public void expPointcut() {
    }

    /**
     * 异常通知
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "expPointcut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        SysExceptionLog exception = new SysExceptionLog();
        HttpServletRequest request = RequestHolder.getRequest();
        String ip = IpUtil.getIpAddress(request);
        exception.setIp(ip);
        String region = searcherService.getRegionInfo(ip);
        exception.setIpSource(region);
        String requestParams = Arrays.toString(joinPoint.getArgs());
        exception.setParams(requestParams);
        exception.setRequestInterface(Objects.requireNonNull(request).getRequestURI());
        String exceptionJson = JSON.toJSONString(e,
                SerializerFeature.DisableCircularReferenceDetect,
                SerializerFeature.WriteMapNullValue);
        exception.setExceptionJson(exceptionJson.substring(0, Math.min(500, exceptionJson.length())));
        exception.setExceptionMessage(e.getMessage());
        exception.setCreateTime(new Date());
        exception.setCreateUserId(String.valueOf(SecurityUtils.getUserId()));
        Map<String, String> osAndBrowserInfo = IpUtil.getOsAndBrowserInfo(request);
        exception.setBrowser(osAndBrowserInfo.get("BROWSER"));
        exception.setPlatform(osAndBrowserInfo.get("OS"));
        String requestMethod = request.getMethod();
        System.out.println("获取请求方式" + requestMethod);
        exception.setRequestWay(requestMethod);
        sysExceptionLogService.save(exception);
    }

}
